
import time
import serial
import threading
import select
import redis

from setting import DOOR_STATUS, CABINET_CURRENT_TEMP
import logging

logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')

logger = logging.getLogger(__name__)

def singleton(cls): # 单例模式装饰器
    instance = None
    lock = threading.Lock()

    def get_instance(*args, **kwargs):
        nonlocal instance
        with lock:
            if not instance:
                instance = cls(*args, **kwargs)
            return instance
    return get_instance

@singleton
class SerialPortMethod: # 串口方法

    def __enter__(self):

        return self

    def __exit__(self, exc_type, exc_val, exc_tb):

        self.ser.close()

    def __init__(self, serial_path="/dev/ttyS3", baud=9600):

        self.serial_path = serial_path

        self.ser = serial.Serial(self.serial_path, baud, 8, "N", timeout=0, stopbits=1)

        self.receive_thread = threading.Thread(target=self.receive_data)

        # 创建一个Redis连接
        self.r = redis.Redis(host='localhost', port=6379, db=0)

        self.is_running = False

    def receive_data(self):

        self.is_running = True

        while self.is_running:
            if self.ser.in_waiting > 0:

                data = self.ser.read(self.ser.in_waiting)

                logger.info(data.hex())

                self.callback_processing(data)

            select.select([self.ser], [], [], 0.1)

    def start_receive_thread(self):

        self.receive_thread.start()

    def stop_receive_thread(self):

        self.is_running = False

        self.receive_thread.join()
  

    def send_data(self, data: str):

        logger.info("send: {}".format(data))
        
        self.ser.write(bytes.fromhex(data))


    def get_door_status(self, raw_command):

        '''获取门状态'''

        door_status = raw_command[6:10]

        logger.info("door_status: {}".format(door_status))

        return door_status
    
    def open_door(self):

        data = "E5 01 01 00 00 12 00 00 00 01 00 00 DC 08".replace(' ', '')

        logger.info("开门")

        self.send_data(data=data)

    def close_door(self):

        data = "E5 01 01 00 00 12 00 00 00 00 00 00 8D C8".replace(' ', '')

        logger.info("关门")
        
        self.send_data(data=data)

    def check_door(self):

        data = "E5 01 00 00 00 12 00 00 00 00 00 00 DC 0D".replace(' ', '')

        logger.info("检查门状态")
        
        self.send_data(data=data)

    def get_temperature(self): # 获取温度
    
        # data = "E5 02 00 0000 10 00000000 0000 F089".replace(' ', '')
        data = "E50200000010000000000000F089"

        logger.info("获取温度")
        
        self.send_data(data=data)
    
    def callback_processing(self, raw_command): # 回调处理

        sensor_address = raw_command[1]

        fun = raw_command[2]

        sn = raw_command[3:5]

        if raw_command.hex() == "e60101000012000000010000d80c":

            logger.info("door_lock_open: {}".format("开锁"))

            self.r.publish(DOOR_STATUS, 'LockOpen') # 发送门锁 状态开

        if sensor_address == 1 and fun == 0: # 如果是检查门锁命令

            door_status = self.get_door_status(raw_command)

            if door_status[3] == 1: # 

                self.r.publish(DOOR_STATUS, 'True') # 发送门状态 开门

            elif door_status[1] == 0 and door_status[3] == 0:  # door_status[1] 值为0是开锁 值为1是关锁

                self.r.publish(DOOR_STATUS, 'False') # 发送门状态 关门


        if raw_command.hex().startswith("e602"):

            temp_raw = raw_command[6: 10]

            temp = int.from_bytes(temp_raw, byteorder='big', signed=True) / 10

            logger.info("温度: {}-解释结果：{}".format(temp_raw, temp))

            self.r.set(CABINET_CURRENT_TEMP, str(temp)) # 设置温度


if __name__ == "__main__":

    with SerialPortMethod() as ser:
        ser.receive_data()
        # 在此之后，你可以继续调用发送数据的方法，而监听线程会在后台一直运行并处理接收到的数据



